/*
 * This source code is part of TWaver 4.0
 *
 * Serva Software PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 * Copyright 2002 - 2011 Serva Software. All rights reserved.
 */

package demo.chart.attachment;

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;
import java.awt.geom.Point2D;
import java.util.ArrayList;
import java.util.List;

import javax.swing.JSplitPane;
import javax.swing.Timer;

import twaver.Element;
import twaver.EnumType;
import twaver.EnumTypeManager;
import twaver.MovableFilter;
import twaver.Node;
import twaver.TDataBox;
import twaver.TUIManager;
import twaver.TWaverConst;
import twaver.TWaverUtil;
import twaver.chart.BarChart;
import twaver.chart.Bubble;
import twaver.chart.RadarAxis;
import twaver.network.TNetwork;
import twaver.table.Category;
import twaver.table.TPropertySheet;
import twaver.table.TPropertySheetPane;
import demo.DemoPane;
import demo.chart.attachment.chartattachment.BarElementAttachcment;
import demo.chart.attachment.chartattachment.BubbleElementAttachcment;
import demo.chart.attachment.chartattachment.DialElementAttachment;
import demo.chart.attachment.chartattachment.ElementAttachment;
import demo.chart.attachment.chartattachment.LineElementAttachcment;
import demo.chart.attachment.chartattachment.PercentElementAttachment;
import demo.chart.attachment.chartattachment.PieElementAttachment;
import demo.chart.attachment.chartattachment.RadarElementAttachment;
import demo.chart.attachment.chartattachment.ScaleElementAttachment;
import demo.chart.attachment.element.BarElement;
import demo.chart.attachment.element.BubbleElement;
import demo.chart.attachment.element.ChartAttachmentElement;
import demo.chart.attachment.element.DialElement;
import demo.chart.attachment.element.LineElement;
import demo.chart.attachment.element.PercentElement;
import demo.chart.attachment.element.PieElement;
import demo.chart.attachment.element.RadarElement;
import demo.chart.attachment.element.ScaleChartElement;
import demo.chart.attachment.element.XYScaleChartElement;

public class ChartAttachmentDemo extends DemoPane {

	private TDataBox box = new TDataBox();
	private TNetwork network = new TNetwork(box);
	private TPropertySheet sheet = new TPropertySheet(box);
	private double startAngle = 0;
	public static Point MOUSELOCATION = null;

	public ChartAttachmentDemo() {
		registerChartAttributes();
		initGUI();
		initBox();
		doNetworkLayout();
	}

	private void registerChartAttributes() {
		//Category
		Category.registerCategory("chart.chart", "Chart");
		Category.registerCategory("chart.abstractchart", "AbstractChart", false);
		Category.registerCategory("chart.scalechart", "ScaleChart", false);
		Category.registerCategory("chart.xyscalechart", "XYScaleChart", false);
		Category.registerCategory("chart.bar", "Bar", true);
		Category.registerCategory("chart.dial", "Dial", true);
		Category.registerCategory("chart.percent", "Percent", true);
		Category.registerCategory("chart.pie", "Pie", true);
		Category.registerCategory("chart.radar", "Radar", true);
		Category.registerCategory("chart.line", "Line", true);
		Category.registerCategory("chart.bubble", "Bubble", true);
		Category.registerCategory("chart.legend", "Legend", false);

		//Enum
		EnumTypeManager.getInstance().registerEnumTypes("DialType",
				new EnumType[] {
						new EnumType(TWaverConst.DIAL_TYPE_WHOLE, "Whole"),
						new EnumType(TWaverConst.DIAL_TYPE_ARC, "Arc") });
		
		EnumTypeManager.getInstance().registerEnumTypes("RadarRingStyle",
				new EnumType[] {
						new EnumType(TWaverConst.RADAE_RING_STYLE_ELLIPSE, "Ellipse"),
						new EnumType(TWaverConst.RADAE_RING_STYLE_LINE, "Line") });
		
		EnumTypeManager.getInstance().registerEnumTypes("PercentMarkerStartPostion",
				new EnumType[] {
						new EnumType(TWaverConst.PERCENT_MARKER_START_WITH_EDGE, "Edge"),
						new EnumType(TWaverConst.PERCENT_MARKER_START_WITH_BOTTOM, "Bottom") });
		
		EnumTypeManager.getInstance().registerEnumTypes("PercentMarkerPostion",
				new EnumType[] {
						new EnumType(TWaverConst.PERCENT_MARKER_POSITION_DEFAULT, "Default"),
						new EnumType(TWaverConst.PERCENT_MARKER_POSITION_TOP, "Top"),
						new EnumType(TWaverConst.PERCENT_MARKER_POSITION_BOTTOM, "Bottom"),
						new EnumType(TWaverConst.PERCENT_MARKER_POSITION_LEFT, "Left"),
						new EnumType(TWaverConst.PERCENT_MARKER_POSITION_RIGHT, "Right"),
						new EnumType(TWaverConst.PERCENT_MARKER_POSITION_INNER_DEFAULT, "Inner Default"),
						new EnumType(TWaverConst.PERCENT_MARKER_POSITION_INNER_TOP, "Inner Top"),
						new EnumType(TWaverConst.PERCENT_MARKER_POSITION_INNER_BOTTOM, "Inner Bottom"),
						new EnumType(TWaverConst.PERCENT_MARKER_POSITION_INNER_LEFT, "Inner Left"),
						new EnumType(TWaverConst.PERCENT_MARKER_POSITION_INNER_RIGHT, "Inner Right") });
		
		EnumTypeManager.getInstance().registerEnumTypes("DialScaleStyle",
				new EnumType[] {
						new EnumType(TWaverConst.DIAL_SCALE_STYLE_BALL, "Ball"),
						new EnumType(TWaverConst.DIAL_SCALE_STYLE_LINE, "Line") });
		
		EnumTypeManager.getInstance().registerEnumTypes("PercentType",
				new EnumType[] {
						new EnumType(TWaverConst.PERCENT_TYPE_HORIZONTAL, "Horizontal"),
						new EnumType(TWaverConst.PERCENT_TYPE_VERTICAL, "Vertical") });
		
		EnumTypeManager.getInstance().registerEnumTypes("BarType",
				new EnumType[] {
						new EnumType(TWaverConst.BAR_TYPE_DEFAULT, "Default"),
						new EnumType(TWaverConst.BAR_TYPE_GROUP, "Group"),
						new EnumType(TWaverConst.BAR_TYPE_LAYER, "Layer"),
						new EnumType(TWaverConst.BAR_TYPE_PERCENT, "Percent"),
						new EnumType(TWaverConst.BAR_TYPE_STACK, "Stack") });
		
		EnumTypeManager.getInstance().registerEnumTypes("LineType",
				new EnumType[] {
						new EnumType(TWaverConst.LINE_TYPE_DEFAULT, "Default"),
						new EnumType(TWaverConst.LINE_TYPE_AREA, "Area"),
						new EnumType(TWaverConst.LINE_TYPE_POLE, "Pole") });
		
		EnumTypeManager.getInstance().registerEnumTypes("InflexionStyle",
				new EnumType[] {
						new EnumType(TWaverConst.INFLEXION_STYLE_CIRCLE, "Circle"),
						new EnumType(TWaverConst.INFLEXION_STYLE_DIAMOND, "Diamond"),
						new EnumType(TWaverConst.INFLEXION_STYLE_RECTANGLE, "Rectangle"),
						new EnumType(TWaverConst.INFLEXION_STYLE_TRIANGLE, "Triangle"), });

		//xml
		TWaverUtil.registerBeanInfoWithoutDefault(ChartAttachmentElement.class);
		TWaverUtil.registerBeanInfo(ChartAttachmentElement.class, "/demo/chart/attachment/config/AbstractChart.xml");
		TWaverUtil.registerBeanInfo(ScaleChartElement.class, "/demo/chart/attachment/config/AbstractScaleChart.xml");
		TWaverUtil.registerBeanInfo(XYScaleChartElement.class, "/demo/chart/attachment/config/AbstractXYScaleChart.xml");
		TWaverUtil.registerBeanInfo(PieElement.class, "/demo/chart/attachment/config/PieChart.xml");
		TWaverUtil.registerBeanInfo(DialElement.class, "/demo/chart/attachment/config/DialChart.xml");
		TWaverUtil.registerBeanInfo(PercentElement.class, "/demo/chart/attachment/config/PercentChart.xml");
		TWaverUtil.registerBeanInfo(RadarElement.class, "/demo/chart/attachment/config/RadarChart.xml");
		TWaverUtil.registerBeanInfo(BarElement.class, "/demo/chart/attachment/config/BarChart.xml");
		TWaverUtil.registerBeanInfo(LineElement.class, "/demo/chart/attachment/config/LineChart.xml");
		TWaverUtil.registerBeanInfo(BubbleElement.class, "/demo/chart/attachment/config/BubbleChart.xml");

		//attachment
		TUIManager.registerAttachment(ElementAttachment.PIEATTACHMENT, PieElementAttachment.class);
		TUIManager.registerAttachment(ElementAttachment.DIALATTACHMENT, DialElementAttachment.class);
		TUIManager.registerAttachment(ElementAttachment.PERCENTATTACHMENT, PercentElementAttachment.class);
		TUIManager.registerAttachment(ElementAttachment.RADARATTACHMENT, RadarElementAttachment.class);
		TUIManager.registerAttachment(ElementAttachment.BARATTACHMENT, BarElementAttachcment.class);
		TUIManager.registerAttachment(ElementAttachment.LINEATTACHMENT, LineElementAttachcment.class);
		TUIManager.registerAttachment(ElementAttachment.BUBBLEATTACHMENT, BubbleElementAttachcment.class);
	}

	private void initGUI() {
		network.getToolbar().setVisible(false);
		network.setTextureBackground("/demo/chart/attachment/background.png");

		sheet.setFillIndent(false);
		sheet.setIndentOpaque(false);
		sheet.setEditable(true);
		sheet.getTableHeader().setPreferredSize(new Dimension(0, 30));
		TPropertySheetPane sheetPane = new TPropertySheetPane(sheet);

		JSplitPane pane = new JSplitPane();
		pane.setDividerSize(6);
		pane.setLeftComponent(network);
		pane.setRightComponent(sheetPane);
		pane.setDividerLocation(800);
		this.setLayout(new BorderLayout());
		this.add(pane, BorderLayout.CENTER);
	}

	private void initBox() {
		Element barListElement = createBarListElement();
		box.addElement(createBarElement());
		box.addElement(createDialElement());
		box.addElement(createPercentElement());
		box.addElement(createPieElement());
		box.addElement(createLineElement());
		box.addElement(createRadarElement());
		box.addElement(barListElement);
		box.addElement(createBubbleListElement());

		BarChart chart = (BarChart) barListElement.getBusinessObject();
		chart.setBarType(TWaverConst.BAR_TYPE_GROUP);
		chart.setValueTextVisible(false);
	}

	private Element createBubbleListElement() {
		int[] style = new int[] {
				TWaverConst.INFLEXION_STYLE_DIAMOND,
				TWaverConst.INFLEXION_STYLE_CIRCLE,
				TWaverConst.INFLEXION_STYLE_RECTANGLE,
				TWaverConst.INFLEXION_STYLE_TRIANGLE };
		BubbleElement element = new BubbleElement();
		TDataBox box = new TDataBox();
		int len = style.length;
		for (int i = 0; i < len; i++) {
			Element node = new Node();
			node.setName("e" + (i + 1));
			node.putChartColor(TWaverUtil.getRandomColor());
			node.putChartBubbleStyle(style[i]);
			for (int j = 1; j < 10; j++) {
				Bubble bubble = new Bubble(j * 10, 10 + 80 * Math.random(), 6);
				node.addChartBubble(bubble);
			}
			box.addElement(node);
		}
		element.putClientProperty(ElementAttachment.CHARTBOX, box);
		return element;
	}

	private Element createBarListElement() {
		BarElement barElement = new BarElement();
		TDataBox box = getValusListBox(2, 3, 100);
		barElement.putClientProperty(ElementAttachment.CHARTBOX, box);
		barElement.putClientProperty(ScaleElementAttachment.XSCALETEXTLIST, getScaleList(2));
		return barElement;
	}

	private Element createLineElement() {
		LineElement lineElement = new LineElement();
		TDataBox box = getValusListBox(3, 10, 100);
		lineElement.putClientProperty(ElementAttachment.CHARTBOX, box);
		lineElement.putClientProperty(ScaleElementAttachment.XSCALETEXTLIST, getScaleList(10));
		return lineElement;
	}

	private Element createRadarElement() {
		RadarElement radarElement = new RadarElement();
		TDataBox box = getValusListBox(2, 5, 100);
		radarElement.putClientProperty(ElementAttachment.CHARTBOX, box);
		radarElement.putClientProperty(RadarElementAttachment.RADARAXISLIST, getRadarScaleList(5));
		return radarElement;
	}

	private Element createBarElement() {
		BarElement barElement = new BarElement();
		TDataBox box = getValueBox(5, 100);
		barElement.putClientProperty(ElementAttachment.CHARTBOX, box);
		return barElement;
	}

	private Element createDialElement() {
		DialElement dialElement = new DialElement();
		TDataBox box = getValueBox(3, 100);
		dialElement.putClientProperty(ElementAttachment.CHARTBOX, box);
		return dialElement;
	}

	private Element createPercentElement() {
		PercentElement percentElement = new PercentElement();
		TDataBox box = getValueBox(3, 100);
		box.getRandomElement().putChartPercentStyle(TWaverConst.PERCENT_STYLE_SEGMENT);
		percentElement.putClientProperty(ElementAttachment.CHARTBOX, box);
		return percentElement;
	}

	private Element createPieElement() {
		PieElement pieElement = new PieElement();
		TDataBox box = getValueBox(5, 100);
		pieElement.putClientProperty(ElementAttachment.CHARTBOX, box);
		return pieElement;
	}

	private List getRadarScaleList(int radarScaleCount) {
		List list = new ArrayList();
		for (int i = 1; i <= radarScaleCount; i++) {
			RadarAxis axis = new RadarAxis(i + "", 0, 100);
			list.add(axis);
		}
		return list;
	}

	private List getScaleList(int scaleCount) {
		List list = new ArrayList();
		for (int i = 1; i <= scaleCount; i++) {
			list.add(i + "");
		}
		return list;
	}

	private TDataBox getValusListBox(int elementCount, int valuesCount, double maxValue) {
		TDataBox box = new TDataBox();
		for (int i = 1; i <= elementCount; i++) {
			Node node = new Node();
			node.setName("e" + i);
			node.putChartColor(TWaverUtil.getRandomColor());
			for (int j = 0; j < valuesCount; j++) {
				node.addChartValue((int)(maxValue * Math.random()));
			}
			box.addElement(node);
		}
		return box;
	}

	private TDataBox getValueBox(int count, double maxValue) {
		TDataBox box = new TDataBox();
		for (int i = 1; i <= count; i++) {
			Node node = new Node();
			node.setName("e" + i);
			node.putChartValue((int)(maxValue / 4 + maxValue * 3 / 4 * Math.random()));
			node.putChartColor(TWaverUtil.getRandomColor());
			box.addElement(node);
		}
		return box;
	}

	private void doNetworkLayout() {
		network.addMovableFilter(new MovableFilter() {
			public boolean isMovable(Element element) {
				return false;
			}
		});
		network.getCanvas().addMouseMotionListener(new MouseMotionListener() {
			public void mouseMoved(MouseEvent e) {
				MOUSELOCATION = e.getPoint();				
			}
			
			public void mouseDragged(MouseEvent e) {
				MOUSELOCATION = e.getPoint();	
			}
		});
		network.getCanvas().addMouseListener(new MouseAdapter() {
			public void mouseExited(MouseEvent e) {
				MOUSELOCATION = null;
			}
		});
		network.addComponentListener(new ComponentAdapter() {
			public void componentResized(ComponentEvent e) {
				Dimension networkSize = network.getSize();
				double w = networkSize.width - 100;
				double h = networkSize.height - 100;
				double ellipseSize = w > h ? h : w;
				ElementAttachment.AttachmentWidth = (int) (ellipseSize / 5);
				ElementAttachment.AttachmentHeight = (int) (ellipseSize / 7);
				if (box.getLastSelectedElement() != null) {
					box.getLastSelectedElement().firePropertyChange(TWaverConst.PROPERTYNAME_LOCATION, Boolean.TRUE, Boolean.FALSE);
				}
			}
		});
		Timer timer = new Timer(100, new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				if(!network.getCanvas().isShowing()){
					return;
				}
				startAngle += 2;
				Dimension networkSize = network.getSize();
				List elements = box.getAllElements();
				if (box.getLastSelectedElement() != null) {
					elements.remove(box.getLastSelectedElement());
				}
				double w = networkSize.width - 2 * ElementAttachment.AttachmentWidth;
				double h = networkSize.height - 2 * ElementAttachment.AttachmentHeight;
				double ellipseSize = w > h ? h : w;
				Point2D.Double center = new Point2D.Double(networkSize.width / 2, networkSize.height / 2);
				int elementCount = elements.size();
				for (int i = 0; i < elementCount; i++) {
					ChartAttachmentElement element = (ChartAttachmentElement) elements.get(i);
					double x = center.x + ellipseSize / 2 * Math.cos((startAngle + 360.0 / elementCount * i) * Math.PI / 180);
					double y = center.y + ellipseSize / 2 * Math.sin((startAngle + 360.0 / elementCount * i) * Math.PI / 180);
					element.setCenterLocation(x / network.getZoom(), y / network.getZoom());
				}
				if (box.getLastSelectedElement() != null) {
					box.getLastSelectedElement().setCenterLocation(networkSize.width / 2 / network.getZoom(), networkSize.height / 2 / network.getZoom());
				}
			}
		});
		timer.start();
	}
}